// features
#![no_std]
#![feature(abi_x86_interrupt)]
#![feature(alloc_error_handler)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(lang_items)]
#![feature(panic_info_message)]
#![feature(prelude_import)]

// extern crates
extern crate alloc;
extern crate core;

// allocator
#[global_allocator]
static A: Allocator = Allocator;

// special mods
mod prelude;
#[allow(unused_imports)]
#[prelude_import]
use prelude::*;

#[macro_use]
mod macros;

// normal code
mod boot;
mod driver;
mod kernel;
mod stdlib;

use crate::boot::bootinfo::{get_bootinfo, BootInfo};
use crate::driver::raw::serial::{init_serial_with_port, SerialPort};
use crate::kernel::x86_64::{idt::*, paging::*};
use crate::stdlib::alloc::*;

#[no_mangle]
extern "C" fn kernel_start() -> ! {
    // init
    let bootinfo = get_bootinfo();
    // serial
    init_serial_with_port(SerialPort::COM1);
    // alloc
    Allocator::init();
    // idt
    bootinfo.idt = generate_idt(bootinfo);
    bootinfo.idt.load();
    // paging
    extern "C" {
        static _kernel_start: u8;
        static _kernel_end: u8;
    }
    let kernel_start = unsafe { &_kernel_start as *const u8 as usize as u64 };
    let kernel_end = unsafe { &_kernel_end as *const u8 as usize as u64 };
    let memblk_kernel = MemoryBlock::new_with_range(kernel_start..kernel_end);
    let memblk_heap = MemoryBlock::new_with_size(kernel_end, 0x10_0000);

    // call main
    kernel::kernel_main(bootinfo);
}

fn generate_idt(bootinfo: &BootInfo) -> IDT {
    let cslm: u16 = bootinfo.cslm;
    IDT {
        divide_by_zero: Default::default(),
        debug: Default::default(),
        nmi: Default::default(),
        break_point: From::from((ih_break_point as InterruptFunc, cslm)),
        overflow: Default::default(),
        bound_range_exceeded: Default::default(),
        invalid_opcode: From::from((ih_invalid_opcode as InterruptFunc, cslm)),
        device_not_available: Default::default(),
        double_fault: From::from((ih_double_fault as InterruptFuncWithErrorCode, cslm)),
        invalid_tss: Default::default(),
        segment_not_present: Default::default(),
        stack_segment_fault: Default::default(),
        general_protection_fault: Default::default(),
        page_fault: From::from((ih_page_fault as InterruptFuncWithErrorCode, cslm)),
        x87_fp_exception: Default::default(),
        alignment: Default::default(),
        machine_check: Default::default(),
        simd_fp_exception: Default::default(),
        virtualization_exception: Default::default(),
        security_exception: Default::default(),
        user_defined: [Default::default(); 224],
        ..IDT::empty()
    }
}

unsafe extern "x86-interrupt" fn ih_break_point(stack_frame: InterruptStackFrame) {
    println!(
        "[DEBUG] break_point occurred RIP: {:X} CS: {:X}",
        stack_frame.instruction_pointer, stack_frame.code_segment
    );
}

unsafe extern "x86-interrupt" fn ih_invalid_opcode(stack_frame: InterruptStackFrame) {
    panic!(
        "invalid_opcode occurred RIP: {:X} CS: {:X}",
        stack_frame.instruction_pointer, stack_frame.code_segment
    );
}

unsafe extern "x86-interrupt" fn ih_double_fault(
    stack_frame: InterruptStackFrame,
    error_code: u64,
) {
    let error_code =
        *(((&stack_frame as *const InterruptStackFrame as usize) - size_of::<u64>()) as *const u64); // 手动修复LLVM的实现错误
    panic!(
        "double_fault occurred RIP: {:X} CS: {:X} ErrorCode: {:X}",
        stack_frame.instruction_pointer, stack_frame.code_segment, error_code
    );
}

unsafe extern "x86-interrupt" fn ih_page_fault(stack_frame: InterruptStackFrame, error_code: u64) {
    let error_code =
        *(((&stack_frame as *const InterruptStackFrame as usize) - size_of::<u64>()) as *const u64); // 手动修复LLVM的实现错误
    panic!(
        "unexcepted page_fault occurred RIP: {:X} CS: {:X} ErrorCode: {:X}",
        stack_frame.instruction_pointer, stack_frame.code_segment, error_code
    );
}
